#pragma once
#include <string>
#include <map>

class AiPlayer;

#define NUM_PLAYERS 10

class AiBrain
{
	friend class AiPlayer;

	enum Stages			{STAGE_PREFLOP, STAGE_FLOP, STAGE_TURN, STAGE_RIVER, STAGE_COUNT};
	enum Phases			{PHASE_EARLY, PHASE_MIDDLE, PHASE_LATE, PHASE_COUNT};
	enum Combinations	{COMB_NOTHING, COMB_TWOPAIRS, COMB_THREE, COMB_FLUSH, COMB_STREET, COMB_FOUR, COMB_FULLHOUSE, COMB_STREETFLASH, COMB_ROYALFLASH, COMB_COUNT};
	enum Hands			{HAND_NOTHING, HAND_TOP_PAIR, HAND_OVER_PAIR, HAND_TWO_PAIRS_OR_MORE, HAND_COUNT};
	enum Positions		{POS_EARLY, POS_MIDDLE, POS_LATE, POS_BLINDS, POS_COUNT};
	enum Raises			{RAISE_NO, RAISE_ONE, RAISE_MORE_THAN_ONE, RAISE_COUNT};
	enum Actions		{ACT_ERROR, ACT_FOLD, ACT_CHECK, ACT_CALL, ACT_RAISE, ACT_ALL_IN, ACT_COUNT};

private:
	class Table
	{
	public:
		virtual Actions GetAction(AiBrain *iBrain, bool iPreflopRaise, int &oRaiseCnt) = 0;
		virtual ~Table() {}
	};


	//--------------------------------------------------------------------------------------------------------------
	struct ActionMatrix
	{
		Actions Action[RAISE_COUNT][POS_COUNT];
	};


	//--------------------------------------------------------------------------------------------------------------
	class PreFlopTable: public Table
	{
		std::map<std::string, ActionMatrix> A[PHASE_COUNT];

	private:
		void FillEarlyPhase();
		void FillMiddlePhase();
		void FillLatePhase();


	public:
		PreFlopTable();
		virtual Actions GetAction(AiBrain *iBrain, bool iPreflopRaise, int &oRaiseCnt);
	};
	friend class PreFlopTable;


	//--------------------------------------------------------------------------------------------------------------
	class FlopTable: public Table
	{
		ActionMatrix AmsWithRaise[PHASE_COUNT][HAND_COUNT];
		ActionMatrix AmsWithoutRaise[PHASE_COUNT][HAND_COUNT];

	private:
		void FillEarlyPhase();
		void FillMiddlePhase();
		void FillLatePhase();

	public:
		FlopTable();
		virtual Actions GetAction(AiBrain *iBrain, bool iPreflopRaise, int &oRaiseCnt);
	};
	friend class FlopTable;


	//--------------------------------------------------------------------------------------------------------------
	class TurnTable: public Table
	{
		ActionMatrix AmsWithRaise[PHASE_COUNT][HAND_COUNT];
		ActionMatrix AmsWithoutRaise[PHASE_COUNT][HAND_COUNT];

	private:
		void FillEarlyPhase();
		void FillMiddlePhase();
		void FillLatePhase();

	public:
		TurnTable();
		virtual Actions GetAction(AiBrain *iBrain, bool iPreflopRaise, int &oRaiseCnt);
	};
	friend class TurnTable;


	//--------------------------------------------------------------------------------------------------------------
	class RiverTable: public Table
	{
		ActionMatrix Ams[PHASE_COUNT][HAND_COUNT];

	private:
		void FillEarlyPhase();
		void FillMiddlePhase();
		void FillLatePhase();

	public:
		RiverTable();
		virtual Actions GetAction(AiBrain *iBrain, bool iPreflopRaise, int &oRaiseCnt);
	};

	friend class RiverTable;

private:
	AiPlayer		*Pl;
	Phases			Phase;
	Stages			Stage;
	Positions		Pos;
	Combinations	Combintation;
	int				HandCardsFromCombination;
	Raises			Raise;
	Hands			Hand;
	int				LastRaiseCount;
//	int				MaxStake;
	int				MaxRaiseCount;
	bool			WasRaisesAfterUs;
// 	int				ColdCollersCount;
// 	int				LimpersCount;
	std::string 	Cards;
	std::string 	Suits;
	char			CardStack[600]; //cards priority
	bool			IsFirstRound;
	bool			FirstTime;
	bool			PreflopRaise;
	AiBrain::Table  *Tables[STAGE_COUNT];
	
	
	CString		ErrMsg;

	struct CombinationInfo
	{
		int groups2;
		int groups3;
		int groups4;
		int street_cards;
		int num_hearts;
		int num_spades;
		int num_clubs;
		int num_diamonds;
		char highest_street_card;
		char street_cards_indeces[50];
		char clubs_cards[7];
		char diamonds_cards[7];
		char hearts_cards[7];
		char spades_cards[7];
		char cards_2[5];
		char cards_3[5];
		char cards_4[5];
	};

private:
	//for combination determing
	void SortCards(char c[100], char s[100], int player_cards[2], int n);
	CombinationInfo GatherCombinationInfo(char c[100], char s[100], int n);
	void ProcessFlashOrStreet(CombinationInfo &info, int player_cards[2]);
	void Process234FullHouse(CombinationInfo &info, int player_cards[2]);

	void DetermineFirstRound();
	void DeterminePhase();
	void DetermineStage();
	void DeterminePosition();
	void DetermineRaises();
	void DetermineHand();
	void DetermineCards();
	bool DetermineCombination(char iTableCards[20][2], const int iSize);
	bool ValidateData();

public:
	AiBrain();
	Actions AiBrain::MakeDecision(AiPlayer *iPlayer, int &oRaiseCnt);
	void			 GetMessage(TCHAR *oBuf);
	~AiBrain();
};
